package ru.amse.tsyganov.jumleditor.editor;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;

import ru.amse.tsyganov.jumleditor.commands.Command;
import ru.amse.tsyganov.jumleditor.commands.CommandFactory;
import ru.amse.tsyganov.jumleditor.commands.ViewsManager;
import ru.amse.tsyganov.jumleditor.model.ActivityGraph;
import ru.amse.tsyganov.jumleditor.model.State;
import ru.amse.tsyganov.jumleditor.model.Transition;
import ru.amse.tsyganov.jumleditor.view.ActivePoint;
import ru.amse.tsyganov.jumleditor.view.ActivityGraphView;
import ru.amse.tsyganov.jumleditor.view.ModelViewMap;
import ru.amse.tsyganov.jumleditor.view.SelectedItems;
import ru.amse.tsyganov.jumleditor.view.StateView;
import ru.amse.tsyganov.jumleditor.view.TrackingRectangle;
import ru.amse.tsyganov.jumleditor.view.TransitionView;

public class SelectionMode extends EditorMode {

	public static final SelectionMode instance = new SelectionMode();
	
	private List<TrackingRectangle> trackingRectangles = 
		new ArrayList<TrackingRectangle>();
	
	private ViewsManager viewsManager;
	private ActivityGraphView<ActivityGraph> activityGraphView;
	private Canvas canvas;
	
	private StateView<? extends State> sv;
	
	private boolean shiftOrCtrlPressed = false;
	private boolean isTracking = false;
	private Rectangle selectingRectangle;
	private Rectangle selectingRectangle2;
	
	private ActivePoint activePoint;
	
	private SelectionMode() {
	}
	
	public void init(
			ViewsManager viewsManager,
			ActivityGraphView<ActivityGraph> actionGraphView,
			Canvas canvas) {
		
		this.viewsManager = viewsManager;
		this.activityGraphView = actionGraphView;
		this.canvas = canvas;
	}
	
	@Override
	public void setCursor() {
		canvas.setCursor(new Cursor(null, SWT.CURSOR_ARROW));
	}

	@Override
	public void mouseDoubleClick(MouseEvent e) {
		checkState();
	}

	@Override
	public void mouseDown(MouseEvent e) {
		checkState();
		if (e.button != 1) {
			return;
		}
		isTracking = false;
		
		activePoint = EditorUtil.getActivePoint(e.x, e.y);
		
		StateView<? extends State> selectedView = 
			EditorUtil.getStateView(e.x, e.y);
		
		TransitionView<? extends Transition> selectedTransition = 
			EditorUtil.getTransitionView(e.x, e.y);
		
		if (selectedView != null && 
				SelectedItems.items.selectedStates.contains(selectedView)) {
			
		} else 
		if (!shiftOrCtrlPressed && activePoint == null) {
			SelectedItems.items.selectedStates.clear();
			SelectedItems.items.selectedTransitions.clear();
		}
		
		if (activePoint != null) {
			activePoint.move(e.x, e.y);
		} else if (selectedView != null) {
			isTracking = true;
			if (SelectedItems.items.selectedStates.contains(selectedView)) {
				sv = selectedView;
			} else {
				SelectedItems.items.selectedStates.add(selectedView);
			}
		} else if (selectedTransition != null) {
			if (SelectedItems.items.selectedTransitions.contains(selectedTransition)) {
				SelectedItems.items.selectedTransitions.remove(selectedTransition);
			} else {
				SelectedItems.items.selectedTransitions.add(selectedTransition);
			}			
		} else {
			selectingRectangle = new Rectangle(e.x, e.y, 0, 0);
			selectingRectangle2 = selectingRectangle;
		}
		
		trackingRectangles.clear();
		for (StateView<? extends State> v : SelectedItems.items.selectedStates) {
			TrackingRectangle r = new TrackingRectangle(v);
			r.dx = e.x - r.r.x;
			r.dy = e.y - r.r.y;
			trackingRectangles.add(r);
		}
		canvas.redraw();
	}

	@Override
	public void mouseUp(MouseEvent e) {
		checkState();
		isTracking = false;
		selectingRectangle = null;
		selectingRectangle2 = null;
		if (e.button != 1) {
			return;
		}
		
		if (activePoint != null) {
			Command c = activePoint.perform();
			if (c != null) {
				viewsManager.executeCommand(c);
			}
			activePoint = null;
			
		} else {
		
			if (sv != null) {
				sv = null;
				SelectedItems.items.selectedStates.remove(sv);
			}
		
			if (trackingRectangles.size() > 0) {
				for (TrackingRectangle r : trackingRectangles) {
					Command c = CommandFactory.createMoveStateCommand(
						r.view, r.r.x, r.r.y);
					viewsManager.executeCommand(c);
				}
			
				assert viewsManager != null;
			}
		}
		canvas.redraw();
	}
	
	@Override
	public void mouseMove(MouseEvent e) {
		if (activePoint != null) {
			activePoint.move(e.x, e.y);	
		}
		
		if (trackingRectangles.size() > 0) {	
			for (TrackingRectangle r : trackingRectangles) {
				r.r.x = e.x - r.dx;
				r.r.y = e.y - r.dy;
			}
		}
		if (EditorUtil.getStateView(e.x, e.y) != null) {
			canvas.setCursor(new Cursor(null, SWT.CURSOR_SIZEALL));
		} else {
			setCursor();
		}
		ActivePoint p = EditorUtil.getActivePoint(e.x, e.y);
		if (p != null) {
			canvas.setCursor(p.getCursor());
		} 
		
		if (selectingRectangle != null) {
			selectingRectangle.width = e.x - selectingRectangle.x;
			selectingRectangle.height = e.y - selectingRectangle.y;
			
			int w;
			int h;
			int x;
			int y;
			if (selectingRectangle.width > 0) {
				w = selectingRectangle.width;
				x = selectingRectangle.x;
			} else {
				w = -selectingRectangle.width;
				x = selectingRectangle.x - w;
			}
			if (selectingRectangle.height > 0) {
				h = selectingRectangle.height;
				y = selectingRectangle.y;
			} else {
				h = -selectingRectangle.height;
				y = selectingRectangle.y - h;
			}
			selectingRectangle2 = new Rectangle(x, y, w, h);
			
			SelectedItems.items.selectedStates.clear();
			SelectedItems.items.selectedTransitions.clear();
			
			ActivityGraph graph = activityGraphView.getModel();
			for (State s : graph.getPartitions().get(0).getContents()) {
				StateView<? extends State> stateView = 
					ModelViewMap.map.getStatesMap().get(s);
				
				if (stateView.getRectangle().intersects(selectingRectangle2)) {
					SelectedItems.items.selectedStates.add(stateView);
				}
				
				for (Transition t : s.getStateVertex().getOutgoing()) {
					TransitionView<? extends Transition> transitionView =
						ModelViewMap.map.getTransitionsMap().get(t);
					if (selectingRectangle2.contains(transitionView.getStartPoint()) ||
							selectingRectangle2.contains(transitionView.getEndPoint())) {
						SelectedItems.items.selectedTransitions.add(transitionView);
					}
				}
			}
		}
		canvas.redraw();
	}

	@Override
	public void paintControl(PaintEvent e) {
		checkState();
		
		GC gc = e.gc;
		
		if (activePoint != null) {
			activePoint.paintTempResult(gc);
		}
		
		if (isTracking) {
			for (TrackingRectangle r : trackingRectangles) {
				Color blackColor = new Color(null, new RGB(0, 0, 0));
				Color grayColor = new Color(null, new RGB(70, 70, 70));
				gc.setForeground(blackColor);
				gc.setBackground(grayColor);
				gc.setAlpha(100);
				gc.fillRectangle(r.r);
				gc.drawRectangle(r.r);
				gc.setAlpha(255);
			}
		}
		if (selectingRectangle2 != null) {
			gc.setForeground(new Color(null, 0,0,0));
			gc.drawRectangle(selectingRectangle2);
		}
	}
	
	private void checkState() {
		if (viewsManager == null ||
				activityGraphView == null ||
				canvas == null) {
			
			throw new IllegalStateException();
		}
	}
	
	@Override
	public void keyPressed(KeyEvent e) {
		if (e.keyCode == SWT.DEL) {
			
			LinkedList<Command> commands = new LinkedList<Command>();
			for (StateView<? extends State> stateView : SelectedItems.items.selectedStates) {
				commands.add(CommandFactory.createDeleteStateCommand(
						activityGraphView, stateView));
			}
			for (TransitionView<? extends Transition> transitionView : 
				SelectedItems.items.selectedTransitions) {
				
				commands.add(CommandFactory.createDeleteTransitionCommand(
						transitionView));
			}
			
			if (commands.size() > 0) {
				Command c = CommandFactory.createCompositeCommand(commands);
				viewsManager.executeCommand(c);
			}
						
			canvas.redraw();
		} else if (e.keyCode == SWT.SHIFT || e.keyCode == SWT.CTRL){
			shiftOrCtrlPressed = true;
		}
	}

	@Override
	public void keyReleased(KeyEvent e) {
		if (e.keyCode == SWT.SHIFT || e.keyCode == SWT.CTRL){
			shiftOrCtrlPressed = false;
		}
	}
}
